#include "main.h"
#include "Chat.h"

/*
 * dlgClientProc
 * - Message handler for main "client" window
 */
BOOL CALLBACK dlgClientProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static char *szUserID = NULL;	// Holds user ID.
	static bool bConnected = FALSE; // Connected... or not =P

	switch (msg)
	{
	case WM_INITDIALOG:
		{
			/*
			 * Center window on screen
			 */
			CenterOnScreen(hWnd);
			
			/*
			 * Read user ID form parameter sent from DialogBox (main.cpp)
			 */
			dlgReturn *dataReturn = (dlgReturn *)lParam;
			szUserID = (char*)dataReturn->params[0];

			/*
			 * Start winsock
			 */
			if (!WinsockStart(1))
			{
				EndDialog(hWnd, 1);
				return TRUE;
			}

			/*
			 * Disable "Disconnect" menu item.
			 */
			EnableMenu(GetMenu(hWnd), IDM_FILE_DISCONNECT, FALSE);

			/*
			 * Add our own user ID to connected users
			 */
			SendDlgItemMessage(hWnd, IDC_USERS, LB_ADDSTRING, 0, (LPARAM)szUserID);
		}
		break;

	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		/*
		 * File => Connect
		 */
		case IDM_FILE_CONNECT:
			{
				/*
				 * Show connect dialog box. Return non-zero on non-cancel
				 */
				int nRet = DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_CONNECT), hWnd, dlgConnectProc);
				if (nRet != 0)
				{
					/*
					 * Get serverInfo and connect with it
					 */
					SOCKADDR_IN *serverInfo = (SOCKADDR_IN *)nRet;
					char *szBufUserID = (char *)malloc(strlen(szUserID) + 1);
					strcpy(szBufUserID, szUserID);
					if (!WinsockOpen() || !WinsockConnect(hWnd, serverInfo, szBufUserID))
						AddSystemText(GetDlgItem(hWnd, IDC_RICHEDIT), "Connection Failed.");
					else
					{
						/*
						 * Connected
						 */
						bConnected = TRUE;

						/*
						 * Send USER command to server notifying them of our
						 * user ID
						 */
						if (!ChatSend("USER", szUserID))
						{
							EndDialog(hWnd, 1);
							return TRUE;
						}

						/*
						 * We're connected. Party time.
						 */
						AddSystemText(GetDlgItem(hWnd, IDC_RICHEDIT), "Connected");

						/*
						 * Disable "Connect" Enable "Disconnect"
						 */
						EnableMenu(GetMenu(hWnd), IDM_FILE_DISCONNECT);
						EnableMenu(GetMenu(hWnd), IDM_FILE_CONNECT, FALSE);
					}

					free(serverInfo);
					/*
					 * NOTE: We don't free szBufUserID since when the socket is closed,
					 * Socket.cpp will automatically free it.
					 */
				}
			}
			break;

		/*
		 * File => Disconnect
		 */
		case IDM_FILE_DISCONNECT:
			/*
			 * Close our sockets
			 */
			if (!WinsockClose(1))
			{
				EndDialog(hWnd, 1);
				return TRUE;
			}

			/*
			 * Not connected
			 */
			bConnected = FALSE;

			/*
			 * Clear users connected list
			 * And add ourself
			 */
			SendDlgItemMessage(hWnd, IDC_USERS, LB_RESETCONTENT, 0, 0);
			SendDlgItemMessage(hWnd, IDC_USERS, LB_ADDSTRING, 0, (LPARAM)szUserID);

			/*
			 * Tell user we're not connected
			 */
			AddSystemText(GetDlgItem(hWnd, IDC_RICHEDIT), "Disconnected");

			/*
			 * Disable "Disconnect", Enable "Connect"
			 */
			EnableMenu(GetMenu(hWnd), IDM_FILE_DISCONNECT, FALSE);
			EnableMenu(GetMenu(hWnd), IDM_FILE_CONNECT);
			break;

		/*
		 * File => Exit
		 */
		case IDM_FILE_EXIT:
			/*
			 * Send close message
			 */
			SendMessage(hWnd, WM_CLOSE, 0, 0);
			break;

		/*
		 * Send Button
		 */
		case IDC_SEND:
			{
				/*
				 * Make sure we're connected
				 */
				if (!bConnected)
				{
					MessageBox(hWnd, "You must be connected first.", "Error", MB_ICONERROR | MB_OK);
					return TRUE;
				}

				/*
				 * Make sure we entered data to send
				 */
				int nLength = GetWindowTextLength(GetDlgItem(hWnd, IDC_EDIT_MSG));
				if (nLength > 0)
				{
					char *szMsg = (char *)malloc(nLength + 1);
					GetDlgItemText(hWnd, IDC_EDIT_MSG, szMsg, nLength + 1);

					/*
					 * Send "MESG" command. We don't add the data to our own rich edit box
					 * because the server will reply with a "MESG" command of it's own with 
					 * the colors and such. Then we'll add it =)
					 */
					ChatSend("MESG", szMsg);

					free(szMsg);

					/*
					 * Clear edit box
					 */
					SetDlgItemText(hWnd, IDC_EDIT_MSG, "");
				}
			}
			break;
		}
		break;

	case WM_SOCKET_ASYNC:
		switch (WSAGETSELECTEVENT(lParam))
		{
		case FD_READ:
			{
				/*
				 * Read command
				 */
				char *type = (char *)malloc(5);
				WinsockReadType((SOCKET)wParam, type);

				// USER - Add user to connected users list
				if (type != NULL && strcmp(type, "USER") == 0)
				{
					/*
					 * Connected user ID incoming
					 */
					char *data = NULL;
					if (!WinsockReadData((SOCKET)wParam, &data))
					{
						EndDialog(hWnd, 1);
						return TRUE;
					}

					/*
					 * Add user ID to list
					 */
					SendDlgItemMessage(hWnd, IDC_USERS, LB_ADDSTRING, 0, (LPARAM)data);

					free(data);
				}

				// CLER - Clear connected users list
				else if (type != NULL && strcmp(type, "CLER") == 0)
				{
					char *data = NULL;
					if (!WinsockReadData((SOCKET)wParam, &data))
					{
						EndDialog(hWnd, 1);
						return TRUE;
					}
					free(data);

					/*
					 * Clear list
					 */
					SendDlgItemMessage(hWnd, IDC_USERS, LB_RESETCONTENT, 0, 0);
				}

				// MESG - Message incoming
				else if (type != NULL && strcmp(type, "MESG") == 0)
				{
					char *data = NULL;
					if (!WinsockReadData((SOCKET)wParam, &data))
					{
						EndDialog(hWnd, 1);
						return TRUE;
					}

					/*
					 * Split string by |.|
					 * Format: name|.|color|.|message
					 */
					char *szName = strtok(data, "|.|");
					COLORREF crText = atoi(strtok(NULL, "|.|"));
					char *szMsg = strtok(NULL, "|.|");

					/*
					 * Add it to rich edit box
					 */
					AddChatMsg(GetDlgItem(hWnd, IDC_RICHEDIT), szName, crText, szMsg);

					free(data);
				}

				// CONN - User connected
				else if (type != NULL && strcmp(type, "CONN") == 0)
				{
					char *data = NULL;
					if (!WinsockReadData((SOCKET)wParam, &data))
					{
						EndDialog(hWnd, 1);
						return TRUE;
					}

					/*
					 * Split string by |.|
					 * Format: name|.|color
					 */
					char *szName = strtok(data, "|.|");
					COLORREF crText = atoi(strtok(NULL, "|.|"));

					char *szMsg = (char *)malloc(strlen(szName) + 11);
					sprintf(szMsg, "%s Connected", szName);

					/*
					 * Notify to rich edit
					 */
					AddNotify(GetDlgItem(hWnd, IDC_RICHEDIT), szMsg, crText);

					free(data);
					free(szMsg);
				}

				// DISC - User disconnected
				else if (type != NULL && strcmp(type, "DISC") == 0)
				{
					char *data = NULL;
					if (!WinsockReadData((SOCKET)wParam, &data))
					{
						EndDialog(hWnd, 1);
						return TRUE;
					}

					/*
					 * Split string by |.|
					 * Format: name|.|color
					 */
					char *szName = strtok(data, "|.|");
					COLORREF crText = atoi(strtok(NULL, "|.|"));

					char *szMsg = (char *)malloc(strlen(szName) + 14);
					sprintf(szMsg, "%s Disconnected", szName);

					/*
					 * Notify to rich edit
					 */
					AddNotify(GetDlgItem(hWnd, IDC_RICHEDIT), szMsg, crText);

					free(data);
					free(szMsg);
				}

				free(type);
			}
			break;

		case FD_CLOSE:
			/*
			 * Close socket (only one is open...)
			 */
			if (!WinsockClose(1))
			{
				EndDialog(hWnd, 1);
				return TRUE;
			}

			/*
			 * Not connected
			 */
			bConnected = FALSE;

			/*
			 * Clear users connected list
			 * And add ourself
			 */
			SendDlgItemMessage(hWnd, IDC_USERS, LB_RESETCONTENT, 0, 0);
			SendDlgItemMessage(hWnd, IDC_USERS, LB_ADDSTRING, 0, (LPARAM)szUserID);

			/*
			 * Disable "Disconnect" Enable "Connect"
			 */
			EnableMenu(GetMenu(hWnd), IDM_FILE_DISCONNECT, FALSE);
			EnableMenu(GetMenu(hWnd), IDM_FILE_CONNECT);
			AddSystemText(GetDlgItem(hWnd, IDC_RICHEDIT), "Server Closed Connection");
			break;
		}
		break;

	case WM_CLOSE:
		/*
		 * End Winsock
		 */
		WinsockEnd(1);
		EndDialog(hWnd, 1);
		break;

	default:
		return FALSE;
	}
	return TRUE;
}